﻿Public Class IClassTypeRing : Implements IComparable(Of IClassTypeRing)
    Private sRingNo As String

    Public Left As Double = 0
    Public Right As Double = Integer.MaxValue
    Public Top As Double = 0
    Public Down As Double = Integer.MaxValue

    Public Property RingNo() As String  '环编号
        Get
            Return sRingNo
        End Get
        Set(ByVal value As String)
            sRingNo = value
        End Set
    End Property
    Private sRingName As String
    Public Property RingName() As String
        Get
            Return sRingName
        End Get
        Set(ByVal value As String)
            sRingName = value
        End Set
    End Property
    Public Property RingDescription() As String
        Get
            Return getRingString()
        End Get
        Set(ByVal value As String)

        End Set
    End Property
    '保存Arcgis对象
    Private _arcgisObeject As Object
    Public Property GeometryObject As Object
        Get
            Return _arcgisObeject
        End Get
        Set(ByVal value As Object)
            _arcgisObeject = value
        End Set
    End Property
    Public Sub SetRingNo(ByVal pRingNo As String)
        sRingNo = pRingNo
    End Sub
    Public Function GetRingNo() As String
        GetRingNo = sRingNo
    End Function
    Private startNode As TypeNode  '开始节点

    Public Function getStartNode() As TypeNode
        getStartNode = startNode
    End Function
    '是否是最小环的标志
    Private bMinRing As Boolean = True
    Public Function isMinRing() As Boolean
        isMinRing = bMinRing
    End Function
    Public Sub setMinRing(ByVal pMiniRing As Boolean)
        bMinRing = pMiniRing
    End Sub

    Private dblArea As Double = 0


    Private nodeList() As TypeNode '节点列表
    Public Function getNodeList() As TypeNode()
        getNodeList = nodeList
    End Function
    Public Sub setNodeLis(ByVal tNodeList() As TypeNode)
        '节点列表中，最尾端不包括开始节点
        Dim nodeCount As Integer
        nodeList = tNodeList
        If tNodeList(UBound(tNodeList)).sNodeNo = tNodeList(LBound(tNodeList)).sNodeNo Then
            '头一个节点和最后的节点重复，需要提出一个节点
            nodeCount = UBound(tNodeList) - LBound(tNodeList) - 1
        Else
            nodeCount = UBound(tNodeList) - LBound(tNodeList)
        End If

        ReDim nodeList(nodeCount)
        Dim i = 0
        For Each tmpNode As TypeNode In tNodeList
            nodeList(i) = tmpNode
            i = i + 1


            '获取范围
            If Left <= tmpNode.longitude Then '经度
                Left = tmpNode.longitude
            End If

            If Right >= tmpNode.longitude Then
                Right = tmpNode.longitude
            End If

            If Top <= tmpNode.latitude Then '纬度
                Top = tmpNode.latitude
            End If

            If Down >= tmpNode.latitude Then
                Down = tmpNode.latitude
            End If

        Next


        startNode = nodeList(0)

    End Sub



    Public bDeleteFlag As Boolean '删除标志
    Public Function getRingString() As String
        '获取环的字符串表示方式
        Dim strRingString As String = ""
        For Each tmpNode As TypeNode In nodeList
            strRingString = strRingString & tmpNode.sNodeNo & "_"
        Next
        getRingString = strRingString & startNode.sNodeNo
    End Function

    Public Function getNodeCount() As Integer
        getNodeCount = nodeList.GetLength(0)
    End Function


    Public Function isSamRing(ByRef tmpRing1 As IClassTypeRing, ByRef tmpRing2 As IClassTypeRing) As Boolean
        '  Debug.Print("比较环：")
        '  Debug.Print(tmpRing1.getRingString & ";" & tmpRing2.getRingString)
        '判断两个环是不是同一个环
        isSamRing = False
        If tmpRing1.getNodeCount <> tmpRing2.getNodeCount Then
            '节点个数不一样，不是同一个环
            Exit Function
        End If

        '查找2个环的相同起点
        Dim ringModel As Integer
        Dim sameDirection As Boolean = True
        ringModel = 0
        For Each tmpNode As TypeNode In tmpRing2.nodeList
            If tmpNode.sNodeNo = tmpRing1.startNode.sNodeNo Then
                '探测方向一致
                Dim midIndex, midIndex1 As Integer
                midIndex = 1
                midIndex1 = (midIndex + ringModel) Mod tmpRing1.getNodeCount()
                If tmpRing1.nodeList(midIndex).sNodeNo = tmpRing2.nodeList(midIndex1).sNodeNo Then
                    '如果一致,
                    sameDirection = True
                Else
                    sameDirection = False
                End If

                Exit For
            End If
            ringModel = ringModel + 1
        Next

        Dim i, index As Integer
        i = 0
        For Each tmpNode As TypeNode In tmpRing1.nodeList
            If sameDirection Then
                '同向
                index = (i + ringModel) Mod tmpRing1.getNodeCount()
            Else
                '逆向
                '                index = (tmpRing1.getNodeCount() - ((i + ringModel) Mod tmpRing1.getNodeCount())) Mod tmpRing1.getNodeCount()
                index = (tmpRing1.getNodeCount() - i + ringModel) Mod tmpRing1.getNodeCount()


            End If

            If tmpNode.sNodeNo = tmpRing2.nodeList(index).sNodeNo Then
            Else
                '节点位序不一致，不是同一个环
                Exit Function
            End If
            i = i + 1
        Next

        isSamRing = True


    End Function


    '构造函数
    Public Sub New(ByRef tmpLine1 As TypeLine, ByRef tmpLine2 As TypeLine)
        '根据两条边，构建一个环。每一条线的起点是另一条线的终点
        Dim newStartNode, newEndNode, innerNodes() As TypeNode
        Dim innerNodeCount As Integer = 0
        Dim startPos As Integer = 0
        newStartNode = tmpLine1.startNode
        newEndNode = tmpLine2.endNode

        If tmpLine1.startNode.sNodeNo = tmpLine2.startNode.sNodeNo Then
            '如果两条线的方向一致，将后一条线换方向
            tmpLine2.reverseLine()
        End If


        '起点
        Me.startNode = tmpLine1.startNode
        ReDim Preserve innerNodes(0)
        innerNodes(0) = tmpLine1.startNode

        '第一条线
        If tmpLine1.getLineType = ClassConsManager.LineTypeEnum.COMBIN_LINE Then
            '是复合线，需要取出内部节点
            innerNodeCount = tmpLine1.getInnerNodes().GetLength(0)
            startPos = innerNodes.GetLength(0)
            ReDim Preserve innerNodes(innerNodeCount)
            For Each tmpNode As TypeNode In tmpLine1.getInnerNodes
                innerNodes(startPos) = tmpNode
                startPos = startPos + 1
            Next
        End If

        '第一条线的终点
        startPos = innerNodes.GetLength(0)
        ReDim Preserve innerNodes(innerNodes.GetLength(0))
        innerNodes(startPos) = tmpLine1.endNode


        '第二条线
        If tmpLine2.getLineType = ClassConsManager.LineTypeEnum.COMBIN_LINE Then
            '是复合线，需要取出内部节点
            startPos = innerNodes.GetLength(0)
            innerNodeCount = innerNodes.GetLength(0) + tmpLine2.getInnerNodes().GetLength(0) - 1
            ReDim Preserve innerNodes(innerNodeCount)
            For Each tmpNode As TypeNode In tmpLine2.getInnerNodes
                innerNodes(startPos) = tmpNode
                startPos = startPos + 1
            Next
        Else
            '不是复合线，是最终的闭环线
        End If
        Me.nodeList = innerNodes

    End Sub


    '构造函数
    Public Sub New(ByVal tNodeList() As TypeNode)
        setNodeLis(tNodeList)
    End Sub
    ''' <summary>
    ''' 判断tmpRing1 是否包含tmpring2，0 没有公共部分 1，tmpring1包含tmpring2，否则ring2 包含ring1
    ''' </summary>
    ''' <param name="tmpRing1"></param>
    ''' <param name="tmpRing2"></param>
    ''' <returns>1，tmpring1包含tmpring2，否则ring2 包含ring1</returns>
    ''' <remarks></remarks>
    Public Function isContain(ByRef tmpRing1 As IClassTypeRing, ByRef tmpRing2 As IClassTypeRing) As Integer
        '判断tmpRing1 是否包含tmpring2，0 没有公共部分 1，tmpring1包含tmpring2，否则ring2 包含ring1
        Dim gt As ClassGraphTool = New ClassGraphTool
        isContain = gt.isInterSectRing(tmpRing1, tmpRing2)
        gt = Nothing
        'isContain = 1
    End Function

    ''' <summary>
    ''' 判断环1是否相交于环2，如果是，返回true ，否则返回false
    ''' </summary>
    ''' <param name="tmpRing1"></param>
    ''' <param name="tmpRing2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>

    Private Function isInterSect(ByRef tmpRing1 As IClassTypeRing, ByRef tmpRing2 As IClassTypeRing) As Boolean
        '判断来环1是否相交于环2，如果是，返回true ，否则返回false
        If tmpRing1.GetRingNo = tmpRing2.GetRingNo Then
            '同一个环，不是包含关系
            isInterSect = False
            Exit Function
        End If

        '  isPointInRing(ByVal n As Long, ByRef ptx() As Double, ByRef pty() As Double, ByVal px As Double, ByVal py As Double) As Boolean
        Dim n As Integer
        n = tmpRing1.getNodeCount
        Dim ptx(n), pty(n) As Double
        Dim i As Integer = 0

        For Each tmpNode As TypeNode In tmpRing1.getNodeList
            ptx(i) = tmpNode.longitude
            pty(i) = tmpNode.latitude
            i = i + 1
        Next
        ptx(i) = tmpRing1.startNode.longitude
        pty(i) = tmpRing1.startNode.latitude


        Dim gt As ClassGraphTool = New ClassGraphTool
        Dim pointOnRing As Boolean = False
        For Each tmpNode As TypeNode In tmpRing2.getNodeList
            '对环2中的所有节点进行循环判断是否在环1中，如果有一个在，说明环1和环2有相较部分，不是最小环，标记为非最小环，推出

            'For Each tNode As TypeNode In tmpRing1.getNodeList
            '    If tNode.sNodeNo = tmpNode.sNodeNo Then
            '        '比较点是环上一点，不进行比较，继续下一个点
            '        pointOnRing = True
            '        Exit For
            '    End If
            'Next

            If pointOnRing = False Then
                '点不在环上，判断一下点是否在环内
                Dim px, py As Double
                px = tmpNode.longitude
                py = tmpNode.latitude
                Dim isInsect = gt.isPointInRing(n, ptx, pty, px, py)

                If isInsect Then
                    '点在环内
                    tmpRing1.setMinRing(False)
                    isInterSect = True

                    Exit Function
                End If
            End If
        Next
        isInterSect = False
    End Function


    Public Function getArea() As Double
        '获取环的区域
        If dblArea <= 0.000000001 Then
            '如果区域为零，需要计算区域面积
            dblArea = calcArea()
        Else
            getArea = dblArea
        End If

    End Function

    Private Function calcArea() As Double
        '进行面积计算
        dblArea = 1.0
    End Function

    Public Sub setArea(ByVal pArea As Double)
        '进行面积计算
        dblArea = pArea
    End Sub
    Public Function CompareTo(ByVal x As IClassTypeRing) As Integer Implements IComparable(Of IClassTypeRing).CompareTo
        If Me.Top = x.Top Then
            If Me.Left = x.Left Then
                If Me.Down = x.Down Then
                    CompareTo = Me.Right.CompareTo(x.Right)
                Else
                    CompareTo = Me.Down.CompareTo(x.Down)
                End If
            Else
                CompareTo = Me.Left.CompareTo(x.Left)
            End If
        Else
            CompareTo = Me.Top.CompareTo(x.Top)
        End If

    End Function
End Class
